import 'dart:async';

import 'package:flutter/widgets.dart';

import 'pp_banner_controller.dart';
import 'pp_banner_indicator.dart';

export 'pp_banner_indicator.dart';

// ignore: must_be_immutable
class PPBanner extends StatefulWidget {
  Function(BuildContext context, int index) itemBuilder;
  ValueChanged<int>? onChanged;
  Function(int index)? onItemTap;
  PPBannerController? controller;
  int itemCount;
  BannerIndicator? indicator;
  bool circular;
  final Duration interval;

  /// Page switching speed
  final int speed;
  final bool autoStart;
  double height;

  /// The fraction of the viewport that each page should occupy.
  ///
  /// Defaults to 1.0, which means each page fills the viewport in the scrolling
  /// direction.
  final double viewportFraction;
  PPBanner({
    Key? key,
    required this.itemBuilder,
    required this.itemCount,
    this.onChanged,
    this.onItemTap,
    this.indicator,
    this.circular = true,
    this.viewportFraction = 1.0,
    this.interval = const Duration(seconds: 3),
    this.speed = 300,
    this.autoStart = true,
    this.height = 150.0,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return PPBannerState();
  }
}

class PPBannerState extends State<PPBanner> {
  PageController? pageController;
  final _globalKey = GlobalKey<PPIndicatorState>();
  int index = 0;
  bool _autoPlay = false;
  bool _animateToPage = false;
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    _initController();
    if (widget.autoStart) {
      start();
    }
    widget.controller?.attach(this);
  }

  @override
  void didUpdateWidget(PPBanner oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.controller?.initialPage != widget.controller?.initialPage ||
        oldWidget.viewportFraction != widget.viewportFraction ||
        oldWidget.circular != widget.circular) {
      _initController(index);
    }

    if (oldWidget.autoStart != widget.autoStart) {
      widget.autoStart ? start() : stop();
    }
  }

  @override
  void dispose() {
    widget.controller?.detach();
    pageController?.dispose();
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    var children = <Widget>[];
    children.add(
      PageView.builder(
        //循环方式改变后要重新build，为了确保index的初始值正确
        key: ValueKey(widget.circular),
        // scrollDirection: widget.direction,
        // reverse: widget.reverse,
        itemCount:
            widget.circular && widget.itemCount != 1 ? null : widget.itemCount,
        onPageChanged: _onPageChanged,
        controller: pageController,
        itemBuilder: (context, index) {
          var realIndex = index % widget.itemCount;
          if (widget.onItemTap != null) {
            return GestureDetector(
              child: widget.itemBuilder(context, realIndex),
              onTap: () {
                widget.onItemTap!(realIndex);
              },
            );
          }
          return widget.itemBuilder(context, realIndex);
        },
      ),
    );

    if (widget.indicator != null) {
      var indicator = PPIndicator(
        key: _globalKey,
        initPage: getIndex(),
        itemCount: widget.itemCount,
        indicator: widget.indicator!,
      );
      children.add(Positioned(
        child: indicator,
        bottom: 0,
        left: 0,
        right: 0,
      ));
    }

    return SizedBox(
      height: widget.height,
      child: Listener(
        child: MouseRegion(
          child: Stack(
            children: children,
          ),
        ),
      ),
    );
  }

  void _initController([int? i]) {
    pageController?.dispose();
    index = i ?? widget.controller?.initialPage ?? 0;

    if (widget.circular) {
      index = widget.itemCount + index;
    } else {
      index = getIndex();
    }

    pageController = PageController(
      initialPage: index,
      viewportFraction: widget.viewportFraction,
    );
  }

  void _onPageChanged(int i) {
    if (widget.circular && i < widget.itemCount) {
      index = widget.itemCount + i;
      pageController!.jumpToPage(index);
      return;
    } else {
      index = i;
    }
    _globalKey.currentState?.update(getIndex());
    if (!_animateToPage && widget.onChanged != null) {
      widget.onChanged!(getIndex());
    }
  }

  int getIndex() {
    return index % widget.itemCount;
  }

  void start() {
    _autoPlay = true;
    _start();
  }

  void stop() {
    _autoPlay = false;
    _timer?.cancel();
  }

  void _start() {
    if (!_autoPlay || widget.itemCount < 2) {
      return;
    }
    _timer?.cancel();
    _timer = Timer.periodic(widget.interval, (timer) {
      animateToPage(
        widget.circular ? index + 1 : (index + 1) % widget.itemCount,
        duration: Duration(milliseconds: widget.speed),
        curve: Curves.easeOut,
      );
    });
  }

  Future<void> animateToPage(
    int page, {
    required Duration duration,
    required Curve curve,
  }) async {
    if (widget.itemCount < 2) {
      return;
    }

    int dest = page % widget.itemCount;

    //不循环
    if (!widget.circular) {
      var cur = getIndex();
      page = dest;
      var last = widget.itemCount - 1;
      if (page == cur ||
          (cur == 0 && page == last) ||
          //到最后一个page后，如果没有自动播放则什么也不做，否则需要回到第一个page
          (!_autoPlay && cur == last && page == 0)) {
        return;
      }
    } else {
      int distance = dest - getIndex();
      //检查是目标页是否当前页
      if (distance == 0) {
        return;
      }
    }

    _animateToPage = true;

    return pageController
        ?.animateToPage(page, duration: duration, curve: curve)
        .then((e) {
      _globalKey.currentState?.update(getIndex());
      if (widget.onChanged != null) widget.onChanged!(dest);
      _animateToPage = false;
    });
  }
}
